package com.java.stack;

/**
 * 使用栈模拟一个表达式结果
 */
public class Calculator {

    public static void main(String[] args) {

        String expression = "70+2*6-4";

        //创建两个栈，数栈；符号栈
        ArrayStack2 numStack = new ArrayStack2(10);
        ArrayStack2 operStack = new ArrayStack2(10);

        //定义需要的变量
        int index = 0;
        int num1 = 0;
        int num2 = 0;
        int oper = 0;
        int res = 0;
        char ch = ' '; //将每次扫描得到的char保存到ch

        String keepNum = "";//用于接

        //while循环扫描expression
        while (true){
            //依次扫描得到每一个字符
            ch = expression.substring(index , index+1).charAt(0);//每次得到一个

            //判断ch是什么，做相应的处理
            //如果是运算符,做相应的判断
            if (operStack.ifOper(ch)){
                //判断当前的符号栈是否为空
                if (!operStack.isEmpty()){//不为空，就还需判断符号的优先级
                    //operStack.priority(ch)：当前扫描到的符号；operStack.priority(operStack.peek())：栈顶的符号
                    //如果小于，就从数栈中pop两个数，从符号栈pop出一个符号，进行运算，得到的结果入数栈，再讲当前符号入符号栈
                    if (operStack.priority(ch) <= operStack.priority(operStack.peek())){
                        num1 = numStack.pop();
                        num2 = numStack.pop();
                        oper = operStack.pop();
                        res = numStack.cal(num1 , num2 , oper);
                        //把运算得到的结果 入数栈
                        numStack.push(res);
                        //把当前的符号入符号栈
                        operStack.push(ch);
                    }else {//大于，直接入符号栈
                        operStack.push(ch);
                    }
                }else {//符号栈为空
                    //直接加入栈
                    operStack.push(ch);
                }

            }else {//如果是运算符,则直接入数栈
//                numStack.push(ch);//这样扫描得到的是字符1 ‘1’ ， 不是 1
//                numStack.push(ch - 48);//相差48，啊是克码表


                //上面的判断，对于两位数的数字就会产生错误
                //思路：就处理数，需要向表达式的index后再看一位，就数就扫描，符号才入栈
                //所以要定义一个字符串变量

                keepNum += ch;

                //如果ch已经是表达式的最后一位，就直接入栈
                if (index == expression.length()-1){
                    numStack.push(Integer.parseInt(keepNum));
                }else {

                    //判断下一个字符是不是数字,是就继续扫描;如果是符号直接入栈
                    if (operStack.ifOper(expression.substring(index + 1, index + 2).charAt(0))) {
                        //如果后一位是运算符，则入栈
                        numStack.push(Integer.parseInt(keepNum));
                        //重要！！！ 清空keepNum
                        keepNum = "";
                    }
                }
            }

            //让index + 1 , 判断是否扫描到表达式的最后
            index ++;
            if (index >= expression.length()){
                break;
            }
        }

        //扫描完毕，就依次从数栈和符号栈pop出，进行运算
        while (true){
            //如果符号栈为空，则计算到最后的结果，数栈中就只有一个结果，就是最后的结果
            if (operStack.isEmpty()){
                break;
            }
            num1 = numStack.pop();
            num2 = numStack.pop();
            oper = operStack.pop();
            res = numStack.cal(num1 , num2 , oper);
            //把运算得到的结果 入数栈
            numStack.push(res);
        }


        System.out.println("表达式:"+expression +"="+ res);

    }

}


//定义一个ArrayStack 表示栈
class ArrayStack2{

    private int maxSize;//栈的大小
    private int[] stack;// 数组，数组模拟栈
    private int top = -1; //表示栈顶， 初始化为-1表示没有数据

    //构造器
    public ArrayStack2(int maxSize){
        this.maxSize = maxSize;
        stack = new int[this.maxSize]; //初始化栈的大小
    }

    /**
     * 可以返回当前栈顶的值，但不是真正的pop
     * @return
     */
    public int peek(){
        return stack[top];
    }


    //栈满
    public boolean ifFull(){
        return top == maxSize - 1;//表示栈满
    }

    //栈空
    public boolean isEmpty(){
        return top == -1; //栈空
    }


    //入栈
    public void push(int value){
        //先判断栈是否满
        if (ifFull()){
            System.out.println("栈满");
            return;
        }
        top++;
        stack[top] = value;
    }


    //出栈：将栈顶的数据返回
    public int pop(){
        //先判断是否为空
        if (isEmpty()){
            throw new  RuntimeException("栈中没有数据,栈空");
        }

        int value = stack[top]; //栈顶数据
        top--;
        return value;
    }

    //遍历栈中的数据:从栈顶往下遍历
    public void list(){

        if (isEmpty()){
            System.out.println("栈中没有数据,栈空");
            return;
        }

        //从栈顶往下遍历
        for (int i = top ; i>=0 ; i--){
            System.out.println("栈中索引为"+i +"的数据为:"+stack[i]);
        }

    }


    /**
     * 判断符号优先级，使用数字代表
     * @param oper
     * @return
     */
    public int priority(int oper){
        if (oper=='*' || oper=='/'){
            return 1;
        }else if (oper=='+' || oper=='-'){
            return 0;
        }else {
            return -1;
        }
    }

    /**
     * 判断是否是运算符
     */
    public boolean ifOper(char val){
        return val=='+' || val=='-' || val=='*' || val=='/';
    }

    /**
     * 计算
     */
    public int cal(int num1 , int num2 , int oper){
        int res = 0; //计算得到的值
        switch (oper){
            case '+':
                res = num1 + num2;
                break;
            case '-':
                res = num2 - num1;
                break;
            case '*':
                res = num1 * num2;
                break;
            case '/':
                res = num2 / num1;
                break;
            default:
                break;
        }
        return res;
    }
















}
